Skip to content

Conversation

maksfb
Copy link
Contributor

@maksfb maksfb commented Aug 19, 2025

This is a follow-up to #150963. X86 HLT instruction may appear in the user-level code, in which case we should treat it as a terminator. Handle it as a non-terminator in the Linux kernel mode.

@llvmbot
Copy link
Member

llvmbot commented Aug 19, 2025

@llvm/pr-subscribers-bolt

Author: Maksim Panchenko (maksfb)

Changes

This is a follow-up to #150963. X86 HLT instruction may appear in the user-level code, in which case we should treat it as a terminator. Handle it as a non-terminator in the Linux kernel mode.


Full diff: https://github.com/llvm/llvm-project/pull/154402.diff

4 Files Affected:

  • (modified) bolt/lib/Core/MCPlusBuilder.cpp (+12-4)
  • (modified) bolt/lib/Rewrite/RewriteInstance.cpp (+4-1)
  • (removed) bolt/test/X86/cfg_build_hlt.s (-17)
  • (added) bolt/test/X86/hlt-terminator.s (+24)
diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp
index d8a2ac6f6837a..7f962e14ea115 100644
--- a/bolt/lib/Core/MCPlusBuilder.cpp
+++ b/bolt/lib/Core/MCPlusBuilder.cpp
@@ -30,6 +30,11 @@ using namespace bolt;
 using namespace MCPlus;
 
 namespace opts {
+cl::opt<bool>
+    TerminalHLT("terminal-x86-hlt",
+                cl::desc("Assume that execution stops at x86 HLT instruction"),
+                cl::init(true), cl::Hidden, cl::cat(BoltCategory));
+
 cl::opt<bool>
     TerminalTrap("terminal-trap",
                  cl::desc("Assume that execution stops at trap instruction"),
@@ -132,10 +137,13 @@ bool MCPlusBuilder::equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B,
 }
 
 bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
-  return (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()) ||
-                 Analysis->isTerminator(Inst)
-             ? !isX86HLT(Inst)
-             : false;
+  if (isX86HLT(Inst))
+    return opts::TerminalHLT;
+
+  if (Info->get(Inst.getOpcode()).isTrap())
+    return opts::TerminalTrap;
+
+  return Analysis->isTerminator(Inst);
 }
 
 void MCPlusBuilder::setTailCall(MCInst &Inst) const {
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index fe4a23cc01382..b2056ba2380fb 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -84,6 +84,7 @@ extern cl::opt<bool> KeepNops;
 extern cl::opt<bool> Lite;
 extern cl::list<std::string> ReorderData;
 extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
+extern cl::opt<bool> TerminalHLT;
 extern cl::opt<bool> TerminalTrap;
 extern cl::opt<bool> TimeBuild;
 extern cl::opt<bool> TimeRewrite;
@@ -2177,7 +2178,9 @@ void RewriteInstance::adjustCommandLineOptions() {
     if (!opts::KeepNops.getNumOccurrences())
       opts::KeepNops = true;
 
-    // Linux kernel may resume execution after a trap instruction in some cases.
+    // Linux kernel may resume execution after a trap or x86 HLT instruction.
+    if (!opts::TerminalHLT.getNumOccurrences())
+      opts::TerminalHLT = false;
     if (!opts::TerminalTrap.getNumOccurrences())
       opts::TerminalTrap = false;
   }
diff --git a/bolt/test/X86/cfg_build_hlt.s b/bolt/test/X86/cfg_build_hlt.s
deleted file mode 100644
index a78134df34014..0000000000000
--- a/bolt/test/X86/cfg_build_hlt.s
+++ /dev/null
@@ -1,17 +0,0 @@
-## Check CFG for halt instruction
-
-# RUN: %clang %cflags %s -static -o %t.exe -nostdlib
-# RUN: llvm-bolt %t.exe --print-cfg --print-only=main -o %t 2>&1 | FileCheck %s --check-prefix=CHECK-CFG
-# RUN: llvm-objdump -d %t --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN
-
-# CHECK-CFG: BB Count    : 1
-# CHECK-BIN: <main>:
-# CHECK-BIN-NEXT: f4                            hlt
-# CHECK-BIN-NEXT: c3                            retq
-
-.global main
-  .type main, %function
-main:
-        hlt
-        retq
-.size main, .-main
diff --git a/bolt/test/X86/hlt-terminator.s b/bolt/test/X86/hlt-terminator.s
new file mode 100644
index 0000000000000..8c15d71f337de
--- /dev/null
+++ b/bolt/test/X86/hlt-terminator.s
@@ -0,0 +1,24 @@
+## Check that HLT instruction is handled differently depending on the flags.
+## It's a terminator in the user-level code, but the execution can resume in
+## ring 0.
+
+# RUN: %clang %cflags %s -static -o %t.exe -nostdlib
+# RUN: llvm-bolt %t.exe --print-cfg --print-only=main --terminal-x86-hlt=0 \
+# RUN:   -o %t.ring0 2>&1 | FileCheck %s --check-prefix=CHECK-RING0
+# RUN: llvm-bolt %t.exe --print-cfg --print-only=main \
+# RUN:   -o %t.ring3- 2>&1 | FileCheck %s --check-prefix=CHECK-RING3
+# RUN: llvm-objdump -d %t.ring0 --print-imm-hex | FileCheck %s --check-prefix=CHECK-BIN
+
+# CHECK-RING0: BB Count    : 1
+# CHECK-RING3: BB Count    : 2
+
+# CHECK-BIN: <main>:
+# CHECK-BIN-NEXT: f4                            hlt
+# CHECK-BIN-NEXT: c3                            retq
+
+.global main
+  .type main, %function
+main:
+        hlt
+        retq
+.size main, .-main

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a hyphen at the end of the output filename: %t.ring3-

This is a follow-up to llvm#150963. X86 HLT instruction may appear in the
user-level code, in which case we should treat it as a terminator.
Handle it as a non-terminator in the Linux kernel mode.
@maksfb
Copy link
Contributor Author

maksfb commented Aug 19, 2025

Thanks for the review.

@maksfb maksfb merged commit 0d9b9d1 into llvm:main Aug 19, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants